package com.dhcc.config;

import com.dhcc.service.ReactiveRedisService;
import com.dhcc.service.RedisService;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Redis 自动配置类，自动装配 Redis 连接工厂和模板。
 *
 * @ProjectName Dhcc-Cloud
 * @PackageName dhcc.com.config
 * @Title RedisAutoConfiguration
 * @Date 2024/10/4 下午7:47
 * @Author LiuGuoting
 */
@Configuration
@EnableConfigurationProperties(RedisProperties.class)
@ConditionalOnClass(ReactiveRedisService.class)
public class RedisAutoConfiguration {

    private final RedisProperties redisProperties;
    private static final Logger logger = Logger.getLogger(RedisAutoConfiguration.class.getName());

    public RedisAutoConfiguration(RedisProperties redisProperties) {
        this.redisProperties = redisProperties;
        logger.info("RedisAutoConfiguration 初始化");
    }

    /**
     * 创建 Lettuce 连接工厂，使用连接池参数。
     */
    @SuppressWarnings("ExtractMethodRecommender")
    @Bean
    @ConditionalOnMissingBean
    public LettuceConnectionFactory lettuceConnectionFactory() {
        // 创建连接池配置
        GenericObjectPoolConfig<?> poolConfig = new GenericObjectPoolConfig<>();
        // 设置最大连接数，默认值为10
        poolConfig.setMaxTotal(redisProperties.getPool().getMaxActive() != null ? redisProperties.getPool().getMaxActive() : 10);
        // 设置最大空闲连接数，默认值为5
        poolConfig.setMaxIdle(redisProperties.getPool().getMaxIdle() != null ? redisProperties.getPool().getMaxIdle() : 5);
        // 设置最小空闲连接数，默认值为1
        poolConfig.setMinIdle(redisProperties.getPool().getMinIdle() != null ? redisProperties.getPool().getMinIdle() : 1);
        // 设置最大等待时间，默认值为30000毫秒（30秒）
        poolConfig.setMaxWait(Duration.ofMillis(redisProperties.getPool().getMaxWait() != null ? redisProperties.getPool().getMaxWait() : 30000));

        // 创建 Lettuce 连接池配置
        LettucePoolingClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder()
                .poolConfig(poolConfig)
                .build();

        // 创建 RedisStandaloneConfiguration
        RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
        configuration.setHostName(redisProperties.getHost());
        configuration.setPort(redisProperties.getPort());
        configuration.setDatabase(redisProperties.getDatabase());

        // 可选：设置密码
        if (redisProperties.getPassword() != null && !redisProperties.getPassword().isEmpty()) {
            configuration.setPassword(redisProperties.getPassword());
        }

        // 创建连接工厂
        LettuceConnectionFactory factory = new LettuceConnectionFactory(configuration, clientConfig);
        factory.setShareNativeConnection(true);

        try {
            factory.afterPropertiesSet(); // 初始化连接工厂
            logger.info("Redis连接工厂创建成功");
        } catch (Exception e) {
            // 记录异常并添加上下文信息
            String errorMessage = String.format("与主机创建Redis连接工厂失败: %s and port: %d. Error: %s",
                    redisProperties.getHost(), redisProperties.getPort(), e.getMessage());
            logger.log(Level.SEVERE, errorMessage, e);
            throw new RuntimeException("创建Redis连接工厂失败", e);
        }

        return factory;
    }

    // 创建响应式 Redis 模板
    @Bean
    @ConditionalOnMissingBean
    public ReactiveRedisTemplate<String, Object> reactiveRedisTemplate(ReactiveRedisConnectionFactory connectionFactory) {
        Jackson2JsonRedisSerializer<Object> jsonSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        RedisSerializationContext<String, Object> serializationContext = RedisSerializationContext
                .<String, Object>newSerializationContext()
                .key(new StringRedisSerializer())
                .value(jsonSerializer)
                .hashKey(new StringRedisSerializer())
                .hashValue(jsonSerializer)
                .build();

        logger.info("已成功创建响应式Redis模板");
        return new ReactiveRedisTemplate<>(connectionFactory, serializationContext);
    }

    // 创建传统 Redis 模板
    @Bean
    @ConditionalOnMissingBean
    public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(lettuceConnectionFactory);

        // 设置序列化方式
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));

        template.afterPropertiesSet();
        return template;
    }

    // 创建响应式 Redis 服务实例
    @Bean
    public ReactiveRedisService reactiveRedisService(ReactiveRedisTemplate<String, Object> reactiveRedisTemplate) {
        logger.info("已成功创建响应式-reactiveRedisService操作类实例");
        return new ReactiveRedisService(reactiveRedisTemplate);
    }

    // 创建传统 Redis 服务实例
    @Bean
    public RedisService redisService(RedisTemplate<String, Object> redisTemplate) {
        logger.info("已成功创建传统式-RedisService操作类实例");
        return new RedisService(redisTemplate);
    }
}
